package com.omesoft.hksnore.util.newsnore;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.omesoft.hksnore.util.L;
import com.omesoft.hksnore.util.constant.CusConstant;
import com.omesoft.hksnore.util.file.CreateFiles;
import com.omesoft.hksnore.util.omeview.RecordPragram;
import com.omesoft.hksnore.util.photo.SettingUtil;
import com.omesoft.hksnore.util.snore.SnoreRecord;

import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 鼾声线程
 *
 * @autor omesoft_lgc
 * <p/>
 * create at 2017/5/17 23:59
 */
public class SnoreRecordThread extends Thread {

    private boolean isLoop = true;
    private String fileName;


    private Context context;
    private Handler handler;


    /*******************
     * 录音
     ********************/
    private SnoreRecord recorder;


    public static final float pi = (float) 3.1415926;

    private int length = 256;

    private short[] buffer = new short[FFT.FFT_N << 1];
    /***************************************/
    private RecordPragram recordPragram;
    private ClacSnore cs;
    private String sleepID;
    private long syncTime = 0;
    private long syncDetialTime = 0;
    private long startTime = 0;
    private long recordSnoreTime = 0;
    private int recordCount = 0;
    private long ssTime = 0;
    private int ssCount = 0;
    private boolean isRecord = false;

    public SnoreRecordThread(Context context, Handler handler, String _sleepID, RecordPragram _recordPragram) {
        this.context = context;
        this.handler = handler;
        this.recordPragram = _recordPragram;
        this.sleepID = _sleepID;
        initControl();
    }

    // 初始化控件信息
    private void initControl() {

        fileName = CreateFiles.CreateText(sleepID);
        Log.i("filenameTemp", "filenameTemp    " + fileName);
        cs = new ClacSnore(handler, context);
        buffer = new short[FFT.FFT_N << 1];

    }

    /**
     * 开启录音
     */
    private void startRecord() {
        try {
            isRecord = true;
            recorder.startWirteMP3(buffer, sleepID);
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    isRecord = false;
                    stopRecord();
                    timer.cancel();
                }
            }, 30000);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 停止录音
     */
    private void stopRecord() {
        recorder.closeWriteMP3();
    }

    /**
     * 终止线程
     */
    public void stopSnore() {
        if (isLoop) {
            isLoop = false;
            stopRecord();
        }
    }

    @Override
    public void run() {
        try {
            float realIO[] = new float[FFT.FFT_N];
            int i, j;
            isLoop = true;

            short[] buffer = new short[FFT.FFT_N << 1];

            recorder = SnoreRecord.Create();
            recorder.start();
            startTime = System.currentTimeMillis();
            syncTime = System.currentTimeMillis();
            syncDetialTime = System.currentTimeMillis();
            recordPragram.init(FFT.FFT_N);
            int index = 0;
            int[] tempDB = new int[2];
            while (isLoop) {
                if (recorder != null) {
                    Thread.sleep(50);
                    String nowTestTime = SettingUtil.getTimeDifference(context, startTime, System.currentTimeMillis());
                    sendMsg(CusConstant.TEST_TIME, nowTestTime);//发送监测时长
                    int res = recorder.read(buffer, 0, FFT.FFT_N << 1);
                    String str = "";
                    synchronized (realIO) {

                        for (i = j = 0; i != FFT.FFT_N; i++, j += 2) {
                            realIO[i] = (buffer[j + 1] << 8) | (buffer[j] & 0xff); // signed
                            // short
                            str += realIO[i] + ",";
                        }

                        L.e("xx", "开始拿取DB --");
                        length = up2int(res);
                        short[] tmpBuf = new short[length];
                        System.arraycopy(buffer, 0, tmpBuf, 0, length);
                        Complex[] complexs = new Complex[length];

                        for (int a = 0; a < length; a++) {
                            Short short1 = tmpBuf[a];
                            complexs[a] = new Complex(short1.doubleValue());
                        }
                        fft(complexs, length);
                        for (int b = 0; b < length / 2; b++) {
                            realIO[b] = (complexs[2 * b + 1].getIntValue() > complexs[2 * b].getIntValue()) ? (complexs[2 * b + 1].getIntValue()) : (complexs[2 * b].getIntValue());
                        }
                        cs.analysis(realIO);

                        int[] calcValue64 = cs.getSpectremS();
                        int snoreCount = cs.getSnoreCount();

                        int snoreWave32 = cs.getSumcurWave32();

                        int snoreStopCount = cs.getStopSnoreCount();

                        str = "";

                        /**
                         * 计算2条数据的最大值
                         */
                        int maxDB = recordPragram.getMax(calcValue64);
                        if (index == 1) {
                            index = 0;
                            tempDB[1] = maxDB;

                            maxDB = recordPragram.getMax(tempDB);

                            // 对DB的值保留两位小数
                            DecimalFormat d = new DecimalFormat("#.00");
                            float dB = Float.parseFloat(d.format(maxDB));
                            // 保存DB值到TXT
                            if (fileName.length() > 0) {
                                CreateFiles.print(dB, fileName);
                            }
                            L.e("xx", "2条数据 最大值  maxDB " + maxDB);
                        } else {
                            tempDB[0] = maxDB;

                            index++;
                        }


                        if (recordCount <= 2) {//不超过两次
                            if (cs.isSnore()) {
                                if (isRecord == false) {//是否正在录制，
                                    recordCount += 1;
                                    recordSnoreTime = System.currentTimeMillis();//记录打鼾时间
                                    startRecord();
                                }
                            }

                        }


                        ///仅做打印临时存储
                        for (int a = 0; a < calcValue64.length; a++) {
                            str += calcValue64[a] + ",";
                        }

                        L.e("xx", " 长度: " + realIO.length + " 打鼾次数:" + snoreCount + " 止鼾次数:" + snoreStopCount + " calcValue64:"+calcValue64.length + " snoreWave32:" + snoreWave32 + " 转换后  str " + str);
                        if (System.currentTimeMillis() - syncDetialTime >= 120000) {//2分钟发送同步子表的指令
                            sendMsg(CusConstant.SYNC_DETIAL, "");
                            syncDetialTime = System.currentTimeMillis();

                        } else if (System.currentTimeMillis() - syncTime >= 1800000) {//30分钟发送同步主表指令
                            sendMsg(CusConstant.SYNC_ALL, "");
                            syncTime = System.currentTimeMillis();

                        }
                        synchronized (calcValue64) {
                            recordPragram.update2(true, calcValue64, snoreCount, snoreStopCount);
                        }

                    }
                } else {
                    recorder = SnoreRecord.Create();
                    recorder.start();
                    buffer = new short[FFT.FFT_N << 1];
                    realIO = new float[FFT.FFT_N];
                }

            }

            if (recorder != null) {
                recorder.clean();
                recorder = null;
            }
        } catch (Exception e) {
            // TODO: handle exception
            L.i("Rec E", e.toString());
        }
        Log.e("xx", "2 完事");// 未初始化
        recordPragram.clear();
    }

    /**
     * 向上取最接近iint的2的幂次数.比如iint=320时,返回256
     *
     * @param iint
     * @return
     */
    private int up2int(int iint) {
        int ret = 1;
        while (ret <= iint) {
            ret = ret << 1;
        }
        return ret >> 1;
    }

    /**
     * 发送消息
     */
    private void sendMsg(int w, Object v) {
        Message msg = new Message();
        msg.what = w;
        msg.obj = v;
        handler.sendMessage(msg);
    }


    // 快速傅里叶变换
    public void fft(Complex[] xin, int N) {
        int f, m, N2, nm, i, k, j, L;// L:运算级数
        float p;
        int e2, le, B, ip;
        Complex w = new Complex();
        Complex t = new Complex();
        N2 = N / 2;// 每一级中蝶形的个数,同时也代表m位二进制数最高位的十进制权值
        f = N;// f是为了求流程的级数而设立的
        for (m = 1; (f = f / 2) != 1; m++)
            ; // 得到流程图的共几级
        nm = N - 2;
        j = N2;
        /****** 倒序运算——雷德算法 ******/
        for (i = 1; i <= nm; i++) {
            if (i < j)// 防止重复交换
            {
                t = xin[j];
                xin[j] = xin[i];
                xin[i] = t;
            }
            k = N2;
            while (j >= k) {
                j = j - k;
                k = k / 2;
            }
            j = j + k;
        }
        /****** 蝶形图计算部分 ******/
        for (L = 1; L <= m; L++) // 从第1级到第m级
        {
            e2 = (int) Math.pow(2, L);
            // e2=(int)2.pow(L);
            le = e2 + 1;
            B = e2 / 2;
            for (j = 0; j < B; j++) // j从0到2^(L-1)-1
            {
                p = 2 * pi / e2;
                w.real = Math.cos(p * j);
                // w.real=Math.cos((double)p*j); //系数W
                w.image = Math.sin(p * j) * -1;
                // w.imag = -sin(p*j);
                for (i = j; i < N; i = i + e2) // 计算具有相同系数的数据
                {
                    ip = i + B; // 对应蝶形的数据间隔为2^(L-1)
                    t = xin[ip].cc(w);
                    xin[ip] = xin[i].cut(t);
                    xin[i] = xin[i].sum(t);
                }
            }
        }
    }
}
